﻿
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

namespace Red.Controls.Shell
{
    public partial class RedDialogContent : UserControl
    {
        private RedDialog _dlg;

        public RedDialogContent( RedDialog dlg )
        {
            InitializeComponent();
            _dlg = dlg;
            DataContext = dlg;
        }

        private void AffirmativeButton_Click( object sender, RoutedEventArgs e )
        {
            _dlg.DialogResult = true;
        }

        private void NegativeButton_Click( object sender, RoutedEventArgs e )
        {
            _dlg.DialogResult = false;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public enum RedDialogType
    {
        Ok, OkCancel, YesNo, NoButtons
    }

    /// <summary>
    ///     Base class for simple dialog boxes. Just derive, put your your content inside the Xaml and call Show[Async]
    /// </summary>
    [ContentProperty("Content")]
    public class RedDialog : RedWindow
    {
        #region Dialog

        private bool? _dialogResult;

        #endregion Dialog

        #region Properties

        public new static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register( "Content", typeof( object ), typeof( RedDialog ) );
        
        public static readonly DependencyProperty AffirmativeTextProperty =
            DependencyProperty.Register( "AffirmativeText", typeof( string ), typeof( RedDialog ),
                new FrameworkPropertyMetadata( "Ok" )
                );

        public static readonly DependencyProperty NegativeTextProperty =
            DependencyProperty.Register( "NegativeText", typeof( string ), typeof( RedDialog ),
                new FrameworkPropertyMetadata( "Cancel" )
                );

        public static readonly DependencyProperty TypeProperty =
            DependencyProperty.Register( "Type", typeof( RedDialogType ), typeof( RedDialog ),
                new FrameworkPropertyMetadata( RedDialogType.Ok, OnTypePropertyChanged )
                );

        public static readonly DependencyProperty OwnerSourceProperty =
            DependencyProperty.Register( "OwnerSource", typeof( FrameworkElement ), typeof( RedDialog ),
                new FrameworkPropertyMetadata( OnOwnerSourcePropertyChanged ) );
        
        public new object Content
        {
            get { return (object)GetValue( ContentProperty ); }
            set { SetValue( ContentProperty, value ); }
        }

        /// <summary>
        ///     Text that is shown on OK/Yes button
        /// </summary>
        public string AffirmativeText
        {
            get { return (string)GetValue( AffirmativeTextProperty ); }
            set { SetValue( AffirmativeTextProperty, value ); }
        }

        /// <summary>
        ///     Text that is shown on Cancel/No button
        /// </summary>
        public string NegativeText
        {
            get { return (string)GetValue( NegativeTextProperty ); }
            set { SetValue( NegativeTextProperty, value ); }
        }

        /// <summary>
        ///     Result of the dialog
        /// </summary>
        public new bool? DialogResult 
        {
            get { return _dialogResult; }
            set
            {
                _dialogResult = value;
                Close();
            }
        }

        /// <summary>
        ///     Type of the dialog
        /// </summary>
        public RedDialogType Type
        {
            get { return (RedDialogType)GetValue( TypeProperty ); }
            set { SetValue( TypeProperty, value ); }
        }

        /// <summary>
        ///     Element which serves as an owner source. This is a convenience property. The actual dialog window owner 
        ///     will be the first window up the chain.
        /// </summary>
        public FrameworkElement OwnerSource
        {
            get { return (FrameworkElement)GetValue( OwnerSourceProperty ); }
            set { SetValue( OwnerSourceProperty, value ); }
        }

        #endregion Properties

        #region C-tor

        /// <summary>
        ///     Creates dialog
        /// </summary>
        public RedDialog()
        {
            base.Content = new RedDialogContent( this );
            ShowCloseButton = false;
            ShowMaxRestoreButton = false;
            ShowMinButton = false;
            ShowSystemMenuOnRightClick = false;
            ResizeMode = ResizeMode.NoResize;
            ShowInTaskbar = false;
            SizeToContent = SizeToContent.WidthAndHeight;
            ShowInTaskbar = false;
            WindowStartupLocation = WindowStartupLocation.CenterOwner;
            SetResourceReference( BackgroundProperty, "GrayBrush8" );
        }

        /// <summary>
        ///     Creates dialog with predefined owner source
        /// </summary>
        /// <param name="ownerSource">
        ///     Element which serves as an owner source. This is a convenience parameter. The actual dialog window owner 
        ///     will be the first window up the chain. Usually pass "this" if you are showing dialog from some control.
        /// </param>
        public RedDialog( FrameworkElement ownerSource )
            : this()
        {
            OwnerSource = ownerSource;
        }

        #endregion C-tor

        #region Public methods
        
        /// <summary>
        ///     Shows the dialog
        /// </summary>
        public new bool Show()
        {
            ShowDialog();
            return true.Equals( DialogResult );
        }

        /// <summary>
        ///     Shows the dialog. Async version is like showing the dialog non-modally, with task finished when user takes an action.
        /// </summary>
        public new Task<bool> ShowAsync()
        {
            var tcs = new TaskCompletionSource<bool>();

            Closed += ( object sender, EventArgs e ) => 
                tcs.SetResult(
                    true.Equals( ( (RedDialog)sender ).DialogResult ) 
                    );

            base.Show();
            return tcs.Task;
        }
        
        #endregion Public methods

        #region Event handlers

        private static void OnTypePropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var dialog = d as RedDialog;
            RedDialogContent content = (RedDialogContent)d.GetValue( RedWindow.ContentProperty );            

            switch ( (RedDialogType)e.NewValue )
            {
                case RedDialogType.Ok:
                    content._affirmativeButton.Visibility = Visibility.Visible;
                    content._negativeButton.Visibility = Visibility.Collapsed;
                    break;
                case RedDialogType.OkCancel:
                    content._affirmativeButton.Visibility = Visibility.Visible;
                    content._negativeButton.Visibility = Visibility.Visible;
                    break;
                case RedDialogType.YesNo:
                    content._affirmativeButton.Visibility = Visibility.Visible;
                    content._negativeButton.Visibility = Visibility.Visible;
                    dialog.AffirmativeText = "Yes";
                    dialog.NegativeText = "No";
                    break;
                case RedDialogType.NoButtons:
                    content._affirmativeButton.Visibility = Visibility.Collapsed;
                    content._negativeButton.Visibility = Visibility.Collapsed;
                    break;
            }
        }

        private static void OnOwnerSourcePropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var dialog = d as RedDialog;
            FrameworkElement ownerSource = e.NewValue as FrameworkElement;

            if ( ownerSource != null && ownerSource.IsVisible )
            {
                dialog.Owner = Window.GetWindow( ownerSource );
            }
            else
            { // no owner, so don't let the window to be obscured
                dialog.Owner = null;
                dialog.Topmost = true;
            }
        }

        #endregion Event handlers

    }
}
